<?php

namespace App\Services\Impl;

use App\Constants\AscribeTypeEnum;
use App\Constants\SystemEventTypeEnum;
use App\Model\Business\AppAdSwitch;
use App\Model\Business\Application;
use App\Model\Business\BlackDaily;
use App\Model\Business\BlackIp;
use App\Model\Report\BigDevice;
use App\Model\Report\BigDeviceEvent;
use App\Model\Report\DailyIncrId;
use App\Utils\NumberUtil;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class CommonService
{
    #[Inject]
    protected ReportService $reportService;

    public function getAdSwitch($appId, $channel, $version): array
    {
        $appAdSwitch = AppAdSwitch::findAdSwitch($appId, $channel, $version);

        // 广告开关，默认开
        $adSwitch = $appAdSwitch->ad_switch ?? 1;

        return [
            'adSwitch' => $adSwitch,
        ];
    }

    public function getClientIp()
    {
        $clientIp = request()->getParsedBody()['clientIp'] ?? "";

        if (!empty($clientIp)) {
            return $clientIp;
        }

        return request()->getHeaderLine("x-real-ip") ?? "127.0.0.1";
    }

    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function getBusinessId(): string
    {
        $businessId = request()->getParsedBody()['businessId'] ?? "";

        // 如果不为空，转十进制
        if (!empty($businessId)) {
            return $businessId;
        }

        $dailyIncrId = $this->getDailyIncrId();

        // 十进制转32进制
        return NumberUtil::BIntDecToBase32($dailyIncrId);
    }

    public function getDailyIncrId(): int
    {
        $dailyIncrId = 1;

        $dailyIncrIdModel = DailyIncrId::query()->where("date", date("Y-m-d"))->first();
        if ($dailyIncrIdModel) {
            $dailyIncrId                     = $dailyIncrIdModel->daily_incr_id + 1;
            $dailyIncrIdModel->daily_incr_id = $dailyIncrId;
            $dailyIncrIdModel->save();
        } else {
            DailyIncrId::create([
                'daily_incr_id' => $dailyIncrId,
                'date'          => date("Y-m-d"),
            ]);
        }

        return $dailyIncrId;
    }

    public function getIsAscribeUser($appId, $channel, $oaid): array
    {
        // 公共的, 不固定归因的渠道, 默认是非商店渠道返回固定归因
        $commonNotFixAscribeChannel = ['001', '002', '003', '004', '005'];

        $returnData = [
            // 'isAscribeUser' => false,
            // 'ascribeType' => AscribeTypeEnum::NO->value,
            'ascribeChannel' => $channel
        ];

        if (!in_array($channel, $commonNotFixAscribeChannel)) {
            $returnData['isAscribeUser'] = true;
            $returnData['ascribeType']   = AscribeTypeEnum::FIX->value;
            return $returnData;
        }

        // 是否是归因用户
        $checkIsAscribeUserRet = $this->checkIsAscribeUser($appId, $channel, $oaid);

        $returnData['isAscribeUser']  = $checkIsAscribeUserRet['isAscribe'];
        $returnData['ascribeType']    = $checkIsAscribeUserRet['ascribeType'];
        $returnData['ascribeChannel'] = $checkIsAscribeUserRet['ascribeChannel'];

        return $returnData;
    }

    public function checkIsAscribeUser($appId, $channel, $oaid): array
    {
        $app = Application::find($appId);

        // 如果是003渠道，且没开监测链接
        if ($channel == '003' && !$app->xiaomi_monitor_link_status) {
            // 固定归因
            return [
                'isAscribe'      => 1,
                'ascribeChannel' => $channel,
                'ascribeType'    => AscribeTypeEnum::FIX->value
            ];
        }

        $isAscribe      = 0;
        $ascribeChannel = $channel;
        $ascribeType    = AscribeTypeEnum::NO->value;

        // 到这里，一定是开了监测链接
        $bigDevice = BigDevice::findDevice($appId, $oaid);

        if ($bigDevice) {
            $isAscribe      = 1;
            $ascribeChannel = $bigDevice->ascribe_channel;
            $ascribeType    = AscribeTypeEnum::OAID->value;
        }

        return [
            'isAscribe'      => $isAscribe,
            'ascribeChannel' => $ascribeChannel,
            'ascribeType'    => $ascribeType,
        ];
    }

    public function getAscribeInfo($appId, $oaid): array
    {
        $bigDevice = BigDevice::findDevice($appId, $oaid);

        return [
            'isAscribe'      => (bool)$bigDevice,
            'ascribeChannel' => $bigDevice->ascribe_channel,
        ];
    }

    public function insertBlackDaily(array $params): void
    {
        $ip = $this->getClientIp();

        $app = Application::findOrFail($params['appId']);

        BlackDaily::create([
            'project_id' => $app->project_id,
            'app_id'     => $params['appId'],
            'channel'    => $params['channel'],
            'version'    => $params['version'],
            'ip'         => $ip,
            'oaid'       => $params['oaid'],
            'model'      => $params['model'] ?? '',
            'date'       => Carbon::now()->toDateString()
        ]);
    }

    public function insertBigDevice($projectId, $appId, $oaid, $ua, $ip, $channelType, $channel, $adId,
                                    $adName, $planId, $planName): void
    {
        if (!empty($oaid)) {
            Db::table((new BigDevice())->getTable())->upsert(
                [
                    'project_id'   => $projectId,
                    'app_id'       => $appId,
                    'oaid'         => $oaid,
                    'ua'           => $ua,
                    'ip'           => $ip,
                    'channel_type' => $channelType,
                    'channel'      => $channel,
                    'ad_id'        => $adId,
                    'ad_name'      => $adName,
                    'plan_id'      => $planId,
                    'plan_name'    => $planName,
                ],
                ['app_id', 'oaid'],
                ['ua', 'ip', 'channel_type', 'channel', 'ad_id', 'ad_name', 'plan_id', 'plan_name']);

            // 获取上报方案
            $channelReportConfig = $this->reportService->getChannelReportConfig($appId, $channel);

            $bigDevice = BigDevice::findDevice($appId, $oaid);
            $bigDevice->report_config = $channelReportConfig;
            $bigDevice->save();

            // 大表事件日志
            BigDeviceEvent::insertData($projectId, $appId, $channelType, $channel, '', $oaid, $adId, $adName,
                $planId, $planName, SystemEventTypeEnum::CLICK->value);
        }
    }

    /**
     * 是否指定型号黑名单
     * @param $model
     * @param $channel
     * @return bool
     */
    public function isSpecificModelBlack($model, $channel): bool
    {
        if (!$model) {
            return false;
        }

        $model = strtolower($model);

        if (!str_contains($model, 'r9s') || !in_array($channel, ['002', '005'])) {
            return false;
        }

        return true;
    }
}